home *** CD-ROM | disk | FTP | other *** search
- //
- // TAPAPP.C
- //
- // TAP
- // File Transfer Data Sharing
- // Application Code
- // Revision 1.10
- //
- // 12/28/94 First created
- // 4/24/95 Structures aligned with DWORDS
- // Dynamic extension lists added
- // Fixed EMERGENCY_CLOSE to use bitwise NOT (~)
- //
- #define INCL_DOSERRORS
- #define INCL_WINSHELLDATA
- #define INCL_DOS
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <process.h>
- #include <string.h>
- #include <os2.h>
- #include "tapapp.h"
-
- //
- // PTAPAPPENTRY BuildTapAppEntry_TAP(char *szDescription,
- // char *szProgram,
- // char *szParams,
- // PSZ pszExtension[],
- // ULONG ulNumExtensions);
- //
- // This function allocates and builds a TAPAPPENTRY
- // that should be used to register a TAP application with
- // the TAP servers.
- //
- // Parameters
- // szDescription
- // Description, up to 255 characters, of the application.
- // szProgram
- // Fully qualified path to the TAP executable.
- // szParams
- // Parameters to pass to the TAP program (max: 83 characters)
- // pszExtension
- // A pointer to an array of pointers to strings, each
- // string containing an file extension this application
- // supports.
- // ulNumExtensions
- // Number of extensions the application can handle.
- // If this is zero, pszExtension may be NULL.
- //
- // Returns
- // A pointer to a TAPAPPENTRY.
- //
- // WARNING: The CALLER (that's you) is responsible for
- // freeing this structure after using it.
- // This can be done by calling the standard
- // C function free.
- //
- PTAPAPPENTRY BuildTapAppEntry_TAP(char *szDescription,
- char *szProgram,
- char *szParams,
- PSZ pszExtension[],
- ULONG ulNumExtensions)
- {
- PTAPAPPENTRY pTapAppEntry;
- PEXTENSIONLIST pExtList;
- ULONG i, ulSize;
-
- // Compute the size of the TAPAPPENTRY structure with
- // the extension list appended
- for (i = 0, ulSize = sizeof(TAPAPPENTRY); i < ulNumExtensions; i++)
- ulSize += sizeof(((PEXTENSIONLIST)NULL)->cb) +
- sizeof(((PEXTENSIONLIST)NULL)->szExtension) +
- strlen(pszExtension[i]);
-
- // Allocate a TAPAPPENTRY structure
- pTapAppEntry = (PTAPAPPENTRY) malloc (ulSize);
-
- // Fill in the TAPAPPENTRY structure
- pTapAppEntry->cb = ulSize;
- strcpy(pTapAppEntry -> szDescription, szDescription);
- strcpy(pTapAppEntry -> szProgram, szProgram);
- strcpy(pTapAppEntry -> szParams, szParams);
- pTapAppEntry->ulExtensions = ulNumExtensions;
-
- // Set pExtList to point to the memory location immediately
- // following the TAPAPPENTRY structure
- pExtList = (PEXTENSIONLIST) ((PBYTE)pTapAppEntry + sizeof(TAPAPPENTRY));
-
- // Fill the memory after TAPPAPPENTRY with variable size EXTENSIONLISTs
- for (i = 0; i < ulNumExtensions; i++)
- {
- pExtList -> cb = sizeof(((PEXTENSIONLIST)NULL)->cb) +
- sizeof(((PEXTENSIONLIST)NULL)->szExtension) +
- strlen(pszExtension[i]);
- strcpy(pExtList->szExtension, pszExtension[i]);
-
- // Go to the next EXTENSIONLIST structure
- pExtList = (PEXTENSIONLIST) ((PBYTE)pExtList + pExtList -> cb);
- }
-
- // Warning, the caller must free this up.
- return pTapAppEntry;
- }
-
- //
- // int RegisterApplication_TAP(char *szAppName,
- // PTAPAPPENTRY pTapAppEntry);
- //
- // Registers a TAP Application so that TAP Servers can
- // find it. This need only be done once.
- //
- // Parameters:
- // szAppName
- // Name of the TAP Application
- // pTapAppEntry
- // A pointer to a structure containing
- // information about this TAP application.
- // See TAP.H for the members of this
- // structure. The TAP application is
- // responsible for filling this out
- // completely and correctly.
- //
- // Returns: TRUE on success
- //
- int RegisterApplication_TAP(char *szAppName,
- PTAPAPPENTRY pTapAppEntry)
- {
- int iRet = TRUE;
-
- // Write application data to the INI file
- iRet =
- (INT)PrfWriteProfileData(HINI_SYSTEMPROFILE,
- TAP_INI_APPNAME,
- szAppName,
- (PVOID) pTapAppEntry,
- pTapAppEntry -> cb);
-
- return iRet;
- }
-
- //
- // int DeRegisterApplication_TAP(char *szAppName);
- //
- // Deregisters a TAP Application so that it is unavailable
- // to TAP Servers.
- //
- // Parameters:
- // szAppName
- // Name of the TAP Application
- //
- // Returns: TRUE on success
- //
- int DeRegisterApplication_TAP(char *szAppName)
- {
- int iRet = TRUE;
-
- // Remove application from the INI file
- iRet =
- (INT)PrfWriteProfileData(HINI_SYSTEMPROFILE,
- TAP_INI_APPNAME,
- szAppName,
- NULL,
- 0);
-
- return iRet;
- }
-
- //
- // int OpenFile_TAP(PTAPAPPINFO pTapAppInfo, PHFILE phFile);
- //
- // Opens the current file being transferred for
- // shared reading.
- //
- // Parameters:
- // pTapAppInfo
- // Pointer to the TAP application's instance data.
- // phFile
- // Pointer to an OS/2 file handle. (output)
- //
- // Returns: TRUE on success
- //
- int OpenFile_TAP(PTAPAPPINFO pTapAppInfo, PHFILE phFile)
- {
- APIRET rc;
- ULONG ActionTaken;
- int iRet = TRUE;
-
- // Request exclusive access
- DosRequestMutexSem(pTapAppInfo -> hAppMutex,
- (ULONG)SEM_INDEFINITE_WAIT);
-
- //
- // Open an already existing file for read only access
- //
- // As a child process we really already have an
- // inherited file handle but we're ignoring this fact
- //
- rc = DosOpen(pTapAppInfo -> tiCurrent . szFileName,
- &(pTapAppInfo -> hUserFile),
- &ActionTaken,
- 0,
- FILE_NORMAL,
- OPEN_ACTION_FAIL_IF_NEW |
- OPEN_ACTION_OPEN_IF_EXISTS,
- OPEN_SHARE_DENYNONE |
- OPEN_ACCESS_READONLY,
- NULL);
-
- if (rc)
- iRet = FALSE;
- else
- // Success, return file handle
- *phFile = pTapAppInfo -> hUserFile;
-
- // Release exclusive access
- DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
-
- return iRet;
- }
-
- //
- // int CloseFile_TAP(PTAPAPPINFO pTapAppInfo, HFILE hFile)
- //
- // Closes a the current file opened with OpenFile_TAP.
- //
- // Parameters:
- // pTapAppInfo
- // Pointer to the TAP application's instance data.
- // hFile
- // OS/2 handle to the file to be closed.
- //
- // Returns: TRUE on success
- //
- int CloseFile_TAP(PTAPAPPINFO pTapAppInfo, HFILE hFile)
- {
- int iRet = TRUE;
- APIRET rc;
-
- // Request exclusive access
- DosRequestMutexSem(pTapAppInfo -> hAppMutex,
- (ULONG)SEM_INDEFINITE_WAIT);
-
- // Close file
- rc = DosClose(hFile);
-
- if (rc)
- iRet = FALSE;
-
- // Release exclusive access
- DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
-
- return iRet;
- }
-
- //
- // PTAPAPPINFO InitializeApplication_TAP(int argc, char **argv);
- //
- // Initializes the TAP subsystem. This function must be called
- // as one of the first functions called in the TAP application.
- //
- // Parameters:
- // argc & argv - Standard command line parameters passed
- // to main on startup
- //
- // Returns: A pointer to the TAP instance data on success,
- // otherwise NULL. A NULL return value most likely means this
- // program was NOT started from a TAP server as required.
- //
- PTAPAPPINFO InitializeApplication_TAP(int argc, char **argv)
- {
- PTAPAPPINFO pTapAppInfo = NULL;
- int cnter;
- char szPipeName[CCHMAXPATH];
- HFILE PipeHandle;
- ULONG ActionTaken;
- APIRET rc;
-
- // Parse pipe name from the command line
- for(cnter=0; cnter<argc; cnter++)
- if (!strncmp(argv[cnter], "/TAP=", 5))
- strcpy(szPipeName, (argv[cnter] + 5));
-
- // Open named pipe
- rc = DosOpen(szPipeName,
- &PipeHandle,
- &ActionTaken,
- 0L,
- FILE_NORMAL,
- FILE_OPEN,
- OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE,
- (PEAOP2) NULL);
-
- // Allocate memory
- if (!rc)
- pTapAppInfo = (PTAPAPPINFO) malloc(sizeof(TAPAPPINFO));
-
- if (pTapAppInfo)
- {
- // Initialize TAPAPPINFO structure
- pTapAppInfo -> cb = sizeof(TAPAPPINFO);
- pTapAppInfo -> lShutdown = FALSE;
- pTapAppInfo -> hReadPipe = (HFILE) PipeHandle;
-
- // Create mutex semaphore
- DosCreateMutexSem(NULL,
- &(pTapAppInfo -> hAppMutex),
- 0,
- FALSE);
-
- // Initialize version info
-
- pTapAppInfo -> szVersion[0] = '\0';
- pTapAppInfo -> lVersionAvailable = FALSE;
-
- // Initialize TAPINFO structures
- pTapAppInfo -> tiCurrent . szFileName [0] = '\0';
- pTapAppInfo -> tiCurrent . lCurrentFileSize = TAP_SIZE_UNKNOWN;
- pTapAppInfo -> tiCurrent . lCompleteFileSize = TAP_SIZE_UNKNOWN;
- pTapAppInfo -> tiCurrent . ulFlags = 0;
-
- pTapAppInfo -> tiNext . szFileName [0] = '\0';
- pTapAppInfo -> tiNext . lCurrentFileSize = TAP_SIZE_UNKNOWN;
- pTapAppInfo -> tiNext . lCompleteFileSize = TAP_SIZE_UNKNOWN;
- pTapAppInfo -> tiNext . ulFlags = 0;
-
- // Start TAP Application thread
- #ifdef __BORLANDC__
- _beginthread(ApplicationThread_TAP,
- 8192,
- (void *) pTapAppInfo);
- #else
- _beginthread(ApplicationThread_TAP,
- NULL,
- 8192,
- (void *) pTapAppInfo);
- #endif
- }
-
- return pTapAppInfo;
- }
-
- //
- // int DeInitializeApplication_TAP(PTAPAPPINFO pTapAppInfo);
- //
- // Deinitializes the TAP subsystem.
- //
- // Parameters:
- // pTapAppInfo
- // Pointer to the TAP application's instance data.
- //
- // Returns: TRUE on success
- //
- int DeInitializeApplication_TAP(PTAPAPPINFO pTapAppInfo)
- {
- int iRet = TRUE;
-
- // Request exclusive access
- DosRequestMutexSem(pTapAppInfo -> hAppMutex,
- (ULONG)SEM_INDEFINITE_WAIT);
-
- // Tell the application thread we want to shut down
- pTapAppInfo -> lShutdown = TRUE;
-
- // Release exclusive access
- DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
-
- return iRet;
- }
-
- //
- // int NextFile_TAP(PTAPAPPINFO pTapAppInfo);
- //
- // Waits for the next file in the transfer session
- // or a cancel or an end of batch condition.
- //
- // Parameters:
- // pTapAppInfo
- // Pointer to the TAP application's instance data.
- //
- // Returns: TRUE if another file transfer has started.
- // FALSE if a cancel or end of batch condition has
- // been encountered.
- //
- int NextFile_TAP(PTAPAPPINFO pTapAppInfo)
- {
- int iRet = TRUE;
- int ExitCondition = FALSE;
-
- do
- {
- // Request exclusive access
- DosRequestMutexSem(pTapAppInfo -> hAppMutex,
- (ULONG)SEM_INDEFINITE_WAIT);
-
- // Check if the next packet begins a new file
- ExitCondition = pTapAppInfo -> tiNext.ulFlags & TAP_BOF ? TRUE : FALSE;
-
- // Special condition: if the TAP applicationstarted at this middle
- // of a file, we get no BOF (Begin of File) flag. To detect this
- // condition we check if the current filename is the null string
- // while the next filename is the non-empty string
- if ( (pTapAppInfo -> tiCurrent.szFileName [0] == 0) &&
- (pTapAppInfo -> tiNext.szFileName [0] != 0) )
- ExitCondition = TRUE;
-
- // Check for exit conditions
- if ( (pTapAppInfo -> tiNext.ulFlags & TAP_CANCEL) ||
- (pTapAppInfo -> tiNext.ulFlags & TAP_EOB) )
- {
- iRet = FALSE;
- ExitCondition = TRUE;
- }
-
- // If we're going to exit, update the current data packet
- if (ExitCondition)
- {
- pTapAppInfo -> tiCurrent = pTapAppInfo -> tiNext;
- pTapAppInfo -> tiNext . ulFlags = 0;
- }
-
- // Release exclusive access
- DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
-
- // Wait for 1/4 sec if this loop will repeat
- if (!ExitCondition)
- DosSleep(250);
-
- } while (!ExitCondition);
-
- return iRet;
- }
-
-
- //
- // int MoreData_TAP(PTAPAPPINFO pTapAppInfo);
- //
- // Waits for more data to arrive or one of
- // the following conditions to occur:
- // CANCEL, END OF BATCH, BEGIN NEW FILE, EOF
- //
- // Parameters:
- // pTapAppInfo
- // Pointer to the TAP application's instance data.
- //
- // Returns: TRUE if more data has been received.
- // FALSE if any other condition has occured.
- //
- // If FALSE is returned there will be no more data
- // for the current file. Recommended action is to
- // check the file size and process any still
- // unprocessed data, then call NextFile_TAP
- // to determine if there are any more files to
- // process.
- //
- int MoreData_TAP(PTAPAPPINFO pTapAppInfo)
- {
- int iRet = TRUE;
- int ExitCondition = FALSE;
-
- do
- {
- // Request exclusive access
- DosRequestMutexSem(pTapAppInfo -> hAppMutex,
- (ULONG)SEM_INDEFINITE_WAIT);
-
- // Check for exit conditions that pertain to
- // batch conditions (End of batch, cancel)
- // that should be handled by NextFile
- if ( (pTapAppInfo -> tiNext.ulFlags & TAP_CANCEL) ||
- (pTapAppInfo -> tiNext.ulFlags & TAP_EOB) ||
- (pTapAppInfo -> tiNext.ulFlags & TAP_BOF) )
- {
- iRet = FALSE;
- ExitCondition = TRUE;
- }
- else
- // Check for exit conditions we need
- // to handle here (pertain to the file)
- if (pTapAppInfo -> tiNext.ulFlags & TAP_EOF)
- {
- iRet = FALSE;
- ExitCondition = TRUE;
- pTapAppInfo -> tiNext . ulFlags = 0;
- }
- else
- // Check if the next packet has new data
- if (pTapAppInfo -> tiNext.ulFlags & TAP_NEW_SIZE)
- {
- ExitCondition = TRUE;
- pTapAppInfo -> tiNext . ulFlags = 0;
- }
-
- if (ExitCondition)
- pTapAppInfo -> tiCurrent = pTapAppInfo -> tiNext;
-
- // Release exclusive access
- DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
-
- // Wait for 1/4 sec if this loop will repeat
- if (!ExitCondition)
- DosSleep(250);
-
- } while (!ExitCondition);
-
- return iRet;
- }
-
- //
- // long QueryStatus_TAP(PTAPAPPINFO pTapAppInfo);
- //
- // Queries the status of the current file.
- // This really isn't very useful.
- //
- // Parameters:
- // pTapAppInfo
- // Pointer to the TAP application's instance data.
- //
- // Returns: Bitmapped flags
- //
- long QueryStatus_TAP(PTAPAPPINFO pTapAppInfo)
- {
- long lRet = 0;
-
- // Request exclusive access
- DosRequestMutexSem(pTapAppInfo -> hAppMutex,
- (ULONG)SEM_INDEFINITE_WAIT);
-
- // Return current TAP flags
- lRet = (LONG)(pTapAppInfo -> tiCurrent . ulFlags);
-
- // Release exclusive access
- DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
-
- return lRet;
- }
-
- //
- // int QueryServerVersion_TAP(PTAPAPPINFO pTapAppInfo,
- // char *szVersion);
- //
- // Queries the server version string. This function
- // returns a valid server version string only when it
- // has received at least one packet of information
- // over the named pipe. It's therefore recommended
- // that this not be used until the first call to
- // NextFile_TAP returns.
- //
- // Parameters:
- // pTapAppInfo
- // Pointer to the TAP application's instance data.
- // szVersion
- // Pointer to a memory location of at least 31 bytes
- // to hold the server version string (output)
- //
- // Returns: TRUE on success
- //
- int QueryServerVersion_TAP(PTAPAPPINFO pTapAppInfo,
- char *szVersion,
- ULONG ulBufLen)
- {
- int iRet = TRUE;
- ULONG ulRetries = 10; // Max 10 retries = 2.5 sec
-
- for (;;) {
-
- // Request exclusive access
- DosRequestMutexSem(pTapAppInfo -> hAppMutex,
- (ULONG)SEM_INDEFINITE_WAIT);
-
- if (pTapAppInfo -> lVersionAvailable)
- break;
-
- DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
-
- if (ulRetries-- == 0)
- return (FALSE);
-
- DosSleep (250);
- }
-
- // Make a copy of the server version string
- strncpy (szVersion, pTapAppInfo -> szVersion, ulBufLen - 1);
- szVersion[ulBufLen - 1] = '\0';
-
- // Release exclusive access
- DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
-
- return iRet;
- }
-
- //
- // int QueryFileName_TAP(PTAPAPPINFO pTapAppInfo,
- // char *szFileName);
- //
- // Parameters:
- // pTapAppInfo
- // Pointer to the TAP application's instance data.
- // szFileName
- // Pointer to a memory block of CCHMAXPATH length
- // where the current fully qualified path and file name
- // is copied. (output)
- //
- // Returns: TRUE on success;
- //
- int QueryFileName_TAP(PTAPAPPINFO pTapAppInfo,
- char *szFileName)
- {
- int iRet = TRUE;
-
- // Request exclusive access
- DosRequestMutexSem(pTapAppInfo -> hAppMutex,
- (ULONG)SEM_INDEFINITE_WAIT);
-
- // Make a copy of the fully qualified file name
- strcpy(szFileName, pTapAppInfo -> tiCurrent . szFileName);
-
- // Release exclusive access
- DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
-
- return iRet;
- }
-
- //
- // long QueryCompleteSize_TAP((PTAPAPPINFO pTapAppInfo);
- //
- // Parameters:
- // pTapAppInfo
- // Pointer to the TAP application's instance data.
- //
- // Returns: The size of the complete file or -1 (TAP_SIZE_UNKNOWN)
- // if that size is unknown.
- //
- long QueryCompleteSize_TAP(PTAPAPPINFO pTapAppInfo)
- {
- long lRet = TRUE;
-
- // Request exclusive access
- DosRequestMutexSem(pTapAppInfo -> hAppMutex,
- (ULONG)SEM_INDEFINITE_WAIT);
-
- // Return complete size
- lRet = pTapAppInfo -> tiCurrent . lCompleteFileSize;
-
- // Release exclusive access
- DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
-
- return lRet;
- }
-
- //
- // long QueryCurrentSize_TAP((PTAPAPPINFO pTapAppInfo);
- //
- // Parameters:
- // pTapAppInfo
- // Pointer to the TAP application's instance data.
- //
- // Returns: The size of the current file or -1 (TAP_SIZE_UNKNOWN)
- // if that size is unknown.
- //
- long QueryCurrentSize_TAP(PTAPAPPINFO pTapAppInfo)
- {
- long lRet = TRUE;
-
- // Request exclusive access
- DosRequestMutexSem(pTapAppInfo -> hAppMutex,
- (ULONG)SEM_INDEFINITE_WAIT);
-
- // Return current size
- lRet = pTapAppInfo -> tiCurrent . lCurrentFileSize;
-
- // Release exclusive access
- DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
-
- return lRet;
- }
-
- //
- // void ApplicationThread_TAP(void *AppInfo)
- //
- // -= NOT to be called by any other module =-
- //
- // This is a thread function which serves
- // the purpose of servicing the queue and
- // updating data structures accordingly.
- //
- // This function also handles emergency file
- // closes.
- //
- void ApplicationThread_TAP (void *AppInfo) {
- PTAPAPPINFO pTapAppInfo = (PTAPAPPINFO)AppInfo;
-
- while (!pTapAppInfo->lShutdown) {
- USHORT usPacketSize = 0;
- ULONG ulBytesRead;
- PTAPPACKET pTapPacket;
-
- for (;;) {
- AVAILDATA availData;
- ULONG ulState;
-
- DosPeekNPipe (pTapAppInfo->hReadPipe, &usPacketSize, sizeof (usPacketSize), &ulBytesRead, &availData, &ulState);
-
- // Have we got the whole packet yet ?
-
- if ((ulBytesRead == sizeof (usPacketSize)) && (availData.cbpipe >= usPacketSize))
- break;
-
- // Shutdown on request or if pipe is no longer connected
-
- if ((pTapAppInfo->lShutdown) || (ulState != NP_STATE_CONNECTED))
- goto _ShutDown;
-
- // Not enough data yet, sleep for 1/4 second
-
- DosSleep (250);
- }
-
- // Read packet
-
- pTapPacket = (PTAPPACKET)malloc (usPacketSize);
-
- DosRead(pTapAppInfo->hReadPipe, pTapPacket, usPacketSize, &ulBytesRead);
-
- if (ulBytesRead == usPacketSize) {
- ULONG ulFlags = pTapPacket->flagPacket.usFlags;
-
- if (ulFlags & TAP_EMERGENCY_CLOSE) {
- // Close up file ASAP
- DosClose (pTapAppInfo -> hUserFile);
- // Reset emergency flag, it has been handled
- ulFlags &= ~(ULONG)TAP_EMERGENCY_CLOSE;
- }
-
- // Request exclusive access
- DosRequestMutexSem (pTapAppInfo->hAppMutex, (ULONG)SEM_INDEFINITE_WAIT);
-
- if (ulFlags & TAP_VERSION) {
- LONG lLen = min (sizeof (pTapAppInfo->szVersion) - 1, pTapPacket->versionPacket.usVersionLength);
- strncpy (pTapAppInfo->szVersion, pTapPacket->versionPacket.szVersion, (UINT)lLen);
- pTapAppInfo->szVersion[lLen] = '\0';
- pTapAppInfo -> lVersionAvailable = TRUE;
- }
- else if (ulFlags & TAP_BOF) {
- LONG lLen;
- pTapAppInfo->tiNext.lCurrentFileSize = pTapPacket->beginFilePacket.lCurrentFileSize;
- pTapAppInfo->tiNext.lCompleteFileSize = pTapPacket->beginFilePacket.lCompleteFileSize;
- lLen = min (sizeof (pTapAppInfo->tiNext.szFileName) - 1, pTapPacket->beginFilePacket.usFileNameLength);
- strncpy (pTapAppInfo->tiNext.szFileName, pTapPacket->beginFilePacket.szFileName, (UINT)lLen);
- pTapAppInfo->tiNext.szFileName[lLen] = '\0';
- }
- else if (ulFlags & TAP_NEW_SIZE) {
- pTapAppInfo->tiNext.lCurrentFileSize = pTapPacket->newSizePacket.lCurrentFileSize;
- pTapAppInfo->tiNext.lCompleteFileSize = pTapPacket->newSizePacket.lCompleteFileSize;
- }
-
- // Acknowledge server if requested
- if (ulFlags & TAP_ACKNOWLEDGE) {
- ULONG ulBytesWritten;
- pTapPacket->flagPacket.cb = sizeof (pTapPacket->flagPacket);
- pTapPacket->flagPacket.usFlags = TAP_ACKNOWLEDGE;
- DosWrite (pTapAppInfo->hReadPipe, pTapPacket, pTapPacket->flagPacket.cb, &ulBytesWritten);
- }
-
- pTapAppInfo->tiNext.ulFlags |= ulFlags;
-
- // Release exclusive access
- DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
-
- }
-
- free (pTapPacket);
- }
-
- _ShutDown:
-
- // ***
- // Shutdown
- // ***
-
- // Free mutex
- DosCloseMutexSem(pTapAppInfo -> hAppMutex);
-
- // Shut down pipe
- DosClose(pTapAppInfo -> hReadPipe);
-
- // Free memory
- free (pTapAppInfo);
- }
-
-